/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点，可申请商业授权，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.attendanceshiftgroup.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import vip.xiaonuo.core.consts.CommonConstant;
import vip.xiaonuo.core.enums.CommonStatusEnum;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.DateUtils;
import vip.xiaonuo.facedoor.modular.memberuser.entity.MemberUser;
import vip.xiaonuo.facedoor.modular.memberuser.service.MemberUserService;
import vip.xiaonuo.modular.attendancegroup.entity.AttendanceGroup;
import vip.xiaonuo.modular.attendancegroup.service.AttendanceGroupService;
import vip.xiaonuo.modular.attendancerecord.entity.AttendanceRecord;
import vip.xiaonuo.modular.attendancerecord.service.AttendanceRecordService;
import vip.xiaonuo.modular.attendanceshift.entity.AttendanceShift;
import vip.xiaonuo.modular.attendanceshift.service.AttendanceShiftService;
import vip.xiaonuo.modular.attendanceshiftgroup.entity.AttendanceShiftGroup;
import vip.xiaonuo.modular.attendanceshiftgroup.enums.AttendanceShiftGroupExceptionEnum;
import vip.xiaonuo.modular.attendanceshiftgroup.mapper.AttendanceShiftGroupMapper;
import vip.xiaonuo.modular.attendanceshiftgroup.param.AttendanceShiftGroupParam;
import vip.xiaonuo.modular.attendanceshiftgroup.service.AttendanceShiftGroupService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 考勤班组service接口实现类
 *
 * @author JOE
 * @date 2022-11-11 13:25:25
 */
@Service
@Slf4j
public class AttendanceShiftGroupServiceImpl extends ServiceImpl<AttendanceShiftGroupMapper, AttendanceShiftGroup> implements AttendanceShiftGroupService {

    @Resource
    private AttendanceShiftService shiftService;


    @Autowired
    private MemberUserService memberUserService;

    @Resource
    private AttendanceGroupService groupService;

    @Autowired
    private AttendanceRecordService attendanceRecordService;

    @Override
    public PageResult<AttendanceShiftGroup> page(AttendanceShiftGroupParam attendanceShiftGroupParam) {
        QueryWrapper<AttendanceShiftGroup> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(attendanceShiftGroupParam)) {

            // 根据班组名称 查询
            if (ObjectUtil.isNotEmpty(attendanceShiftGroupParam.getGroupName())) {
                queryWrapper.lambda().like(AttendanceShiftGroup::getGroupName, attendanceShiftGroupParam.getGroupName());
            }
            // 根据启用状态 查询
            if (ObjectUtil.isNotEmpty(attendanceShiftGroupParam.getIsEnable())) {
                queryWrapper.lambda().eq(AttendanceShiftGroup::getIsEnable, attendanceShiftGroupParam.getIsEnable());
            }
        }
        return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
    }

    @Override
    public void memberAttendance(Long memberId, Date time) {
        MemberUser memberUser = memberUserService.getById(memberId);
        //
        if (memberUser == null) {
            log.error("人员已经不存在编号【{}】", memberId);
            return;
        }
        // 查找考勤组
        Long orgId = memberUser.getOrgId();
        AttendanceGroup attendanceGroup = groupService.getOne(new LambdaQueryWrapper<AttendanceGroup>().like(AttendanceGroup::getOrgIds, orgId.toString()));
        if (attendanceGroup == null) {
            log.error("人员【{}】未关联考勤组", memberUser.getName());
            return;
        }
        // 班次id
        String attendanceShiftIds = attendanceGroup.getAttendanceShiftIds();
        if (StringUtils.isAllBlank(attendanceShiftIds)) {
            log.error("考勤组【{}】未选择班次", attendanceGroup.getAttendanceShiftIds());
            return;
        }

        // 当前人所在班次列表
        List<Long> collect = Arrays.stream(attendanceShiftIds.split(",")).map(Long::parseLong).collect(Collectors.toList());
        List<AttendanceShift> shifts = shiftService.list(new LambdaQueryWrapper<AttendanceShift>().in(AttendanceShift::getId, collect));
        if (CollectionUtils.isEmpty(shifts)) {
            log.error("考勤组【{}】未选择班次", attendanceGroup.getAttendanceShiftIds());
            return;
        }
        for (AttendanceShift shift : shifts) {
            // 上班
            up(memberId, time, memberUser, shift);
            // 下班
            down(memberId, time, memberUser, shift);
        }

    }

    private void down(Long memberId, Date time, MemberUser memberUser, AttendanceShift shift) {
        // 下班时间
        Date workOffDate = DateUtils.parseDate(DateUtils.getDate().concat(" ").concat(shift.getOffWorkTime()));
        // 下班开始时间
        Date workOffDateStart = DateUtils.addMinutes(workOffDate, -shift.getOffClockTimeStart());
        // 下班结束时间
        Date workOffDateEnd = DateUtils.addMinutes(workOffDate, shift.getOffClockTimeEnd()==null ? 0: shift.getOffClockTimeEnd());

        if (shift.getIsRangeCustom() != null && shift.getIsRangeCustom()==1){
            this.setDate(workOffDateEnd,23,59,59);
        }

        // 下班
        boolean workOffClick = time.after(workOffDateStart) && time.before(workOffDateEnd);
        if (workOffClick || workOffDateStart.compareTo(time) == 0 || workOffDateEnd.compareTo(time) == 0) {
            AttendanceRecord record = attendanceRecordService.getOne(new LambdaQueryWrapper<AttendanceRecord>().eq(AttendanceRecord::getMemberUserId, memberId)
                    .eq(AttendanceRecord::getAttendanceShiftId, shift.getId()).eq(AttendanceRecord::getEndDate, workOffDate));
            if (record != null) {
                if (record.getClockOutTime() != null && record.getClockOutTime().after(time)) {
                    log.error("已有比此条记录更晚的卡跳过执行，无效记录，跳过执行");
                    return;
                }
                // 早退标志计算
                record.setIsLeaveEarly(time.before(workOffDate) ? 1 : 0);
                record.setClockOutTime(time);
                record.setIsAbsenceDuty(0);
                calcWorkTime(record);
                attendanceRecordService.updateById(record);
            } else {
                log.info("【{}】 未生成考勤记录", memberUser.getName());
            }
        }
    }


    private void up(Long memberId, Date time, MemberUser memberUser, AttendanceShift shift) {
        // 上班时间
        Date workDate = DateUtils.parseDate(DateUtils.getDate().concat(" ").concat(shift.getWorkTime()));
        // 上班开始时间
        Date workDateStart = DateUtils.addMinutes(workDate, shift.getClockTimeStart() == null ? 0 : -shift.getClockTimeStart());
        // 上班结束时间
        Date workDateEnd = DateUtils.addMinutes(workDate, shift.getClockTimeEnd());
        if (shift.getIsRangeCustom() != null && shift.getIsRangeCustom()==1){
            this.setDate(workDateStart,0,0,0);
        }
        // 上班
        boolean workClick = time.after(workDateStart) && time.before(workDateEnd);
        // step1 按照时间过滤掉不是当前班次的
        // step2 判断时间范围
        if (workClick || workDateStart.compareTo(time) == 0 || workDateEnd.compareTo(time) == 0) {
            AttendanceRecord record = attendanceRecordService.getOne(new LambdaQueryWrapper<AttendanceRecord>().eq(AttendanceRecord::getMemberUserId, memberId)
                    .eq(AttendanceRecord::getAttendanceShiftId, shift.getId()).eq(AttendanceRecord::getStartDate, workDate));
            if (record == null) {
                log.error("【{}】未生成考勤记录", memberUser.getName());
                return;
            }
            // step3 上班时间已第一次时间为准、存在不更新
            if (record.getClockInTime() == null) {
                Integer lateMinutes = shift.getLateMinutes();
                if (lateMinutes != 0) {
                    workDate = DateUtils.addTimeMillis(workDate, lateMinutes * 60 * 1000);
                }
                record.setIsLate(time.after(workDate) ? 1 : 0);
                // 未缺勤
                record.setClockInTime(time);
                record.setIsAbsenceDuty(0);
                calcWorkTime(record);
                attendanceRecordService.updateById(record);
            } else {
                log.info("【{}】 已经打过早班卡", memberUser.getName());
            }
        }
    }

    private void setDate(Date d,int h , int m, int s){
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.set(Calendar.HOUR, h);
        cal.set(Calendar.MINUTE,m);
        cal.set(Calendar.SECOND,s);
        d.setTime(cal.getTime().getTime());
    }

    private void calcWorkTime(AttendanceRecord record) {
        if(record.getClockInTime()!=null && record.getClockOutTime()!=null){
            // 获取小时
            double hours = this.getDistanceOfTwoDate(record.getClockInTime(),record.getClockOutTime());
            record.setWorkTime(hours);
        }else{
            record.setWorkTime(null);
        }
    }

    private double getDistanceOfTwoDate(Date before, Date after) {
        long beforeTime = before.getTime();
        long afterTime = after.getTime();
        BigDecimal diff_ms = new BigDecimal(afterTime).subtract(new BigDecimal(beforeTime));

        BigDecimal hours = diff_ms.divide(new BigDecimal("3600000" ),2,BigDecimal.ROUND_HALF_UP);

        return hours.doubleValue();
    }


    @Override
    public List<AttendanceShiftGroup> list(AttendanceShiftGroupParam attendanceShiftGroupParam) {
        return this.list();
    }

    @Override
    public void add(AttendanceShiftGroupParam attendanceShiftGroupParam) {
        AttendanceShiftGroup attendanceShiftGroup = new AttendanceShiftGroup();
        BeanUtil.copyProperties(attendanceShiftGroupParam, attendanceShiftGroup);
        attendanceShiftGroup.setIsEnable(0);
        this.save(attendanceShiftGroup);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(AttendanceShiftGroupParam attendanceShiftGroupParam) {
        // 判断是否有考勤班次
        long count = shiftService.count(new LambdaQueryWrapper<AttendanceShift>().eq(AttendanceShift :: getAttendanceShiftGroupId, attendanceShiftGroupParam.getId()));
        if(count > 0){
            throw new ServiceException(500,"请先清空考勤班次");
        }
        this.removeById(attendanceShiftGroupParam.getId());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(AttendanceShiftGroupParam attendanceShiftGroupParam) {
        AttendanceShiftGroup attendanceShiftGroup = this.queryAttendanceShiftGroup(attendanceShiftGroupParam);
        BeanUtil.copyProperties(attendanceShiftGroupParam, attendanceShiftGroup);

        List<AttendanceShift> shifts = shiftService.list(new LambdaQueryWrapper<AttendanceShift>().eq(AttendanceShift :: getAttendanceShiftGroupId, attendanceShiftGroup.getId()));
        if(shifts.size() > attendanceShiftGroup.getShiftNum()){
            throw new ServiceException(500,"请先删除多余的班次");
        }
        if(attendanceShiftGroup.getShiftNum()>1){
            for(AttendanceShift shift : shifts){
                shift.setIsRangeCustom(0);// 把班次的 考勤时间范围类型修改成自定义
            }
            shiftService.saveOrUpdateBatch(shifts);
        }
        attendanceShiftGroup.setIsEnable(0);
        this.updateById(attendanceShiftGroup);
    }

    @Override
    public AttendanceShiftGroup detail(AttendanceShiftGroupParam attendanceShiftGroupParam) {
        return this.queryAttendanceShiftGroup(attendanceShiftGroupParam);
    }

    /**
     * 获取考勤班组
     *
     * @author JOE
     * @date 2022-11-11 13:25:25
     */
    private AttendanceShiftGroup queryAttendanceShiftGroup(AttendanceShiftGroupParam attendanceShiftGroupParam) {
        AttendanceShiftGroup attendanceShiftGroup = this.getById(attendanceShiftGroupParam.getId());
        if (ObjectUtil.isNull(attendanceShiftGroup)) {
            throw new ServiceException(AttendanceShiftGroupExceptionEnum.NOT_EXIST);
        }
        return attendanceShiftGroup;
    }
}
